1 /** 2 Helper functions for dealing with UDAs, written before hasUDA and 3 others were added to Phobos. 4 */ 5 module unit_threaded.uda; 6 7 private template Identity(T...) if (T.length > 0) { 8 static if (__traits(compiles, { alias x = T[0]; })) 9 alias Identity = T[0]; 10 else 11 enum Identity = T[0]; 12 } 13 14 /** 15 * For the given module, return true if this module's member has 16 * the given UDA. UDAs can be types or values. 17 */ 18 template HasAttribute(alias module_, string moduleMember, alias attribute) { 19 import unit_threaded.meta : importMember; 20 import std.meta : Filter; 21 22 alias member = Identity!(__traits(getMember, module_, moduleMember)); 23 24 static if (!__traits(compiles, __traits(getAttributes, member))) 25 enum HasAttribute = false; 26 else { 27 enum isAttribute(alias T) = is(TypeOf!T == attribute); 28 alias attrs = Filter!(isAttribute, __traits(getAttributes, member)); 29 30 static assert(attrs.length == 0 || attrs.length == 1, 31 text("Maximum number of attributes is 1 for ", attribute)); 32 33 static if (attrs.length == 0) { 34 enum HasAttribute = false; 35 } else { 36 enum HasAttribute = true; 37 } 38 } 39 } 40 41 /** 42 * For the given module, return true if this module's member has 43 * the given UDA. UDAs can be types or values. 44 */ 45 template GetAttributes(alias module_, string member, A) { 46 import unit_threaded.meta : importMember; 47 import std.meta : Filter; 48 49 mixin(importMember!module_(member)); 50 enum isAttribute(alias T) = is(TypeOf!T == A); 51 alias GetAttributes = Filter!(isAttribute, __traits(getAttributes, mixin(member))); 52 } 53 54 /** 55 * Utility to allow checking UDAs regardless of whether the template 56 * parameter is or has a type 57 */ 58 private template TypeOf(alias T) { 59 static if (__traits(compiles, typeof(T))) { 60 alias TypeOf = typeof(T); 61 } else { 62 alias TypeOf = T; 63 } 64 } 65 66 template isTypesAttr(alias T) { 67 import unit_threaded.attrs; 68 69 enum isTypesAttr = is(T) && is(T : Types!U, U...); 70 } 71 72 /* 73 @Types is different from the other UDAs since it's a templated struct 74 None of the templates above work so we special case it here 75 */ 76 77 /// If a test has the @Types UDA 78 enum HasTypes(alias T) = GetTypes!T.length > 0; 79 80 /// Returns the types in the @Types UDA associated to a test 81 template GetTypes(alias T) { 82 import std.meta : Filter, AliasSeq; 83 import std.traits : TemplateArgsOf; 84 85 static if (!__traits(compiles, __traits(getAttributes, T))) { 86 alias GetTypes = AliasSeq!(); 87 } else { 88 alias types = Filter!(isTypesAttr, __traits(getAttributes, T)); 89 static if (types.length > 0) 90 alias GetTypes = TemplateArgsOf!(types[0]); 91 else 92 alias GetTypes = AliasSeq!(); 93 } 94 } 95 96 // copy of recent hasUDA from Phobos here because old 97 // compilers will fail otherwise 98 99 enum hasUtUDA(alias symbol, alias attribute) = getUtUDAs!(symbol, attribute).length > 0; 100 101 template getUtUDAs(alias symbol, alias attribute) { 102 import std.meta : Filter; 103 import std.traits : isInstanceOf; 104 105 template isDesiredUDA(alias toCheck) { 106 static if (is(typeof(attribute)) && !__traits(isTemplate, attribute)) { 107 static if (__traits(compiles, toCheck == attribute)) 108 enum isDesiredUDA = toCheck == attribute; 109 else 110 enum isDesiredUDA = false; 111 } else static if (is(typeof(toCheck))) { 112 static if (__traits(isTemplate, attribute)) 113 enum isDesiredUDA = isInstanceOf!(attribute, typeof(toCheck)); 114 else 115 enum isDesiredUDA = is(typeof(toCheck) == attribute); 116 } else static if (__traits(isTemplate, attribute)) 117 enum isDesiredUDA = isInstanceOf!(attribute, toCheck); 118 else 119 enum isDesiredUDA = is(toCheck == attribute); 120 } 121 122 alias getUtUDAs = Filter!(isDesiredUDA, __traits(getAttributes, symbol)); 123 }